/**
 *
 */
package com.androidnetframe.exception;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * @author 何强
 *         2015-9-6
 */
public class ExceptionHandler {
    public Context context;

    public ExceptionHandler(Context context) {
    }
/*这里是本类使用的方法或接口-------------------------------------------------------------------------------*/

    public class CrashHandler implements UncaughtExceptionHandler {

        public static final String TAG = "CrashHandler";
        /**
         * 错误文件保存的路径
         */
        public String savedFilePath = null;
        //系统默认的UncaughtException处理类
        private UncaughtExceptionHandler mDefaultHandler;
        //CrashHandler实例
        //程序的Context对象
        private Context mContext;
        //用于格式化日期,作为日志文件名的一部分
        private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm");

        /**
         * 保证只有一个CrashHandler实例
         */
        private CrashHandler(Context context) {
            init(context);
        }

        /**
         * 初始化
         *
         * @param context
         */
        public void init(Context context) {
            mContext = context;
            //获取系统默认的UncaughtException处理器
            mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        }

        /**
         * 当UncaughtException发生时会转入该函数来处理
         */
        public int i = 0;

        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            if (!handleException(ex) && mDefaultHandler != null) {
                mDefaultHandler.uncaughtException(thread, ex);
            }

		/*	//在退出程序之前，先把产生的错误文件上传到服务器
			HttpUtils httpUtils = new HttpUtils();
			RequestParams requestParams = new RequestParams();
			requestParams.addBodyParameter("file", new File(savedFilePath));
			httpUtils.send(HttpMethod.GET, "", requestParams, null);
			//将错误文件从磁盘删除
			File f = new File(savedFilePath); // 输入要删除的文件位置
			if(f.exists()){
				f.delete();
			}*/
            //退出程序
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(1);
        }

        /**
         * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
         *
         * @param ex
         * @return true:如果处理了该异常信息;否则返回false.
         */
        private boolean handleException(Throwable ex) {
            if (ex == null) {
                return false;
            }
            //收集设备参数信息
            String errorInfoString = collectErrorInfo(mContext, ex);
            //保存日志文件
            saveCrashInfo2File(errorInfoString);
            return true;
        }

        /**
         * 对Build的字段全部设置为可见,并将其字段的值保存在一个Map中
         */
        public String collectErrorInfo(Context ctx, Throwable ex) {
            StringBuffer sb = new StringBuffer();
				/*获取手机设备相关的信息*/
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi;
            try {
                pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
                if (pi != null) {
                    String versionName = pi.versionName == null ? "null" : pi.versionName;
                    String versionCode = pi.versionCode + "";
                    sb.append("versionName: " + versionName + "\n");
                    sb.append("versionCode: " + versionCode + "\n");
                }
                Field[] fields = Build.class.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    sb.append(field.getName() + ": " + field.get(null).toString() + "\n");
                    //Log.d(TAG, field.getName() + " : " + field.get(null));
                }
            } catch (NameNotFoundException e) {
					/*包名没有发现异常*/
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return sb.append(getErrorDescException(ex)).toString();
        }

        /**
         * 保存错误信息到文件中
         *
         * @param ex
         * @return 返回文件名称, 便于将文件传送到服务器
         */
        private void saveCrashInfo2File(String errorInfoString) {
				/*制作一个唯一的文件名*/
            long timestamp = System.currentTimeMillis();
            String time = formatter.format(timestamp);
            String fileName = "crash-" + time + ".log";
            String path = null;
				/*如果外置Sdcard存在，那么就保存在这里*/
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                path = mContext.getExternalFilesDir(null) + "/" + fileName;
            } else {
					/*如果外置Sdcard不存在，那么就保存到内置的Sdcard中*/
                path = mContext.getFilesDir() + "/" + fileName;
            }
            savedFilePath = path;
            saveFile(savedFilePath, errorInfoString.getBytes());
        }

        /**
         * 将文件保存包一个容器中
         */
        public void saveFile(String path, byte[] errorInfo) {

            File dir = new File(path);
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(dir);
                fos.write(errorInfo);
                fos.flush();
                fos.close();
            } catch (FileNotFoundException e) {
				/*这个异常不可能出现*/
                //Log.e("Test", "My file not found");
                //e.printStackTrace();
            } catch (IOException e) {
				/*这个异常也不可能出现*/
                //e.printStackTrace();
            }
        }
    }

    /*这里是本类使用的方法或类-------------------------------------------------------------------------------*/
    public String getErrorDescException(Throwable ex) {
        StringBuffer sb = new StringBuffer();
        sb.append("Exception: " + ex.getMessage() + "\n");
        StackTraceElement[] elements = ex.getStackTrace();
        for (int i = 0; i < elements.length; i++) {
            sb.append(elements[i].toString() + "\n");
        }
        return sb.toString();
    }

    /*这里是本类使用的方法或类-------------------------------------------------------------------------------*/
/*-->这里是对外提供的方法-------------------------------------------------------------------------*/
    public UncaughtExceptionHandler getUncaughtExceptionHandler(Context context) {
        return new CrashHandler(context);
    }
/*-->这里是对外提供的方法-------------------------------------------------------------------------*/
}
